package com.zzw.globalfilter;

import com.zzw.constant.OrderConstant;
import com.zzw.globalfilter.requestcontext.RequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import reactor.util.context.Context;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.UUID;

/**
 * @author Administrator
 */
public class RequestContextFilter implements GlobalFilter, Ordered {

    private static final Logger logger = LoggerFactory.getLogger(RequestContextFilter.class);

    @Override
    public int getOrder() {
        return OrderConstant.REQUEST_CONTEXT_ORDER;
    }

    private String generateRequestId() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        LocalDateTime requestStartTime = LocalDateTime.now();
        String requestId = generateRequestId();
        ServerHttpRequest request = exchange.getRequest();
        exchange.getResponse().getHeaders().add("request_id", requestId);
        String uri = request.getURI().getRawPath();
        logger.info("请求进入，requestId:{}, 请求路径:{},请求开始时间:{}", requestId, uri, requestStartTime);
        RequestContext context = new RequestContext();
        context.setRequestId(requestId);
        context.setRequestStartTime(requestStartTime);
        return chain.filter(exchange).contextWrite(Context.of(RequestContext.class, context))
                .doOnEach(signal -> {
                    if (signal.isOnComplete()) {
                        LocalDateTime requestEndTime = LocalDateTime.now();
                        logger.info("请求结束，requestId:{}, 请求路径:{},请求结束时间:{},耗时ms:{}", requestId, uri, requestEndTime
                                , ChronoUnit.MILLIS.between(requestStartTime, requestEndTime));
                    }
                });
    }
}
